package com.zygh.dlqwservice.common.aop;

import cn.hutool.core.util.IdUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.zygh.dlqwservice.common.anno.ViLog;
import com.zygh.dlqwservice.common.en.Constant;
import com.zygh.dlqwservice.module.entity.Operation;
import com.zygh.dlqwservice.module.service.IOperationService;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.lang.reflect.Method;
import java.net.InetAddress;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicReference;


/**
 * @author lee
 * 系统日志：切面处理类
 */
@Aspect
@Component
public class SysLogAspect{

    private static final Logger log = LoggerFactory.getLogger(SysLogAspect.class);

    @Resource
    private IOperationService iOperationService;

    /**
     * 定义切点 @Pointcut
     * 在注解的位置切入代码
     */
    @Pointcut("@annotation(com.zygh.dlqwservice.common.anno.ViLog)")
    public void logPoinCut() {
    }

    /**
     * 切面 配置通知
     * @param joinPoint 切入点
     * @throws IOException IO异常
     */
    @AfterReturning("logPoinCut()")
    public void saveOperation(JoinPoint joinPoint) throws IOException {
        //保存日志
        Operation operation = new Operation();
        //从切面织入点处通过反射机制获取织入点处的方法
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        //获取切入点所在的方法
        Method method = signature.getMethod();
        Class<ViLog> v = ViLog.class;
        //获取操作--方法上的ViLog的值
        ViLog viLog = method.getAnnotation(v);
        if (viLog != null) {
            //保存操作事件、日志类型
            String logType = viLog.logType();
            operation.setLogType(logType);
            //功能模块
            String module = viLog.module();
            operation.setModule(module);

        }
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = null;
        if(requestAttributes != null ){
            request  = ((ServletRequestAttributes)requestAttributes ).getRequest();
        }

        assert request != null;
        String httpMethod = request.getMethod();
        // 客户端ip
        String ip = request.getRemoteAddr();
        operation.setTerminalIp(ip);

        //获取头信息
        JSONObject jsonObject = requestHeader(request, operation);
        requestBody(jsonObject,operation);
        setUri(jsonObject,operation);
        operation.setRequestId(IdUtil.simpleUUID());
        operation.setSource("50");
        operation.setParams(operation.getFormatParam());

        String sessionId = request.getSession().getId();
        operation.setSessionId(sessionId);
        //get的参数
        if (Constant.RequestMethod.Get.getMethod().equalsIgnoreCase(httpMethod)) {
            doGet(request,operation);
            //其他方法的参数
        } else {
            otherReqest(request,operation);
        }

        //响应数据
        String result = JSON.toJSONString(request.getAttribute("result"));
        if ("".equals(result)) {
            operation.setResponse("500");
        } else {
            operation.setResponse("200");
        }

        operation.setResponseType("1");
        try {

            Map map =  JSON.parseObject(result,Map.class);
            if (Constant.Other.One.getOther().equals(String.valueOf(map.get(Constant.Other.Code.getOther()))) || Constant.StatusCode.Success.getCode().equals(String.valueOf(map.get(Constant.Other.Code.getOther())))) {
                operation.setResult("成功");
                operation.setErrorCode("");
                operation.setErrorLog("");
            } else {
                operation.setResult("失败");
                operation.setErrorCode((map.get("code") + ""));
                operation.setErrorLog((String) map.get("msg"));
            }
        } catch (Exception e) {
            operation.setResult("成功");
            operation.setErrorCode("");
            operation.setErrorLog("");
        }


        operation.setRequestId(IdUtil.simpleUUID());
        assert viLog != null;
        operation.setContent(viLog.module());
        operation.setResponseTime(1);
        operation.setSourceIp(ip);
        operation.setSourcePort(request.getRemotePort());
        operation.setDestIp(InetAddress.getLocalHost().getHostAddress());
        operation.setDestPort(request.getServerPort());
        operation.setTime(System.currentTimeMillis());
        operation.setState(0);
        iOperationService.save(operation);
    }
    private void doGet(HttpServletRequest request,Operation operation){
        AtomicReference<String> param = new AtomicReference<>("");
        Map<String, String[]> parameterMap = request.getParameterMap();
        Set<String> keys = parameterMap.keySet();
        if (!keys.isEmpty()) {
            for (String key : keys) {
                if (parameterMap.get(key) != null && parameterMap.get(key).length > 0) {
                    param.updateAndGet(v1 -> v1 + key + ":" + parameterMap.get(key)[0] + ",");
                } else {
                    param.updateAndGet(v1 -> v1 + key + ": '',");
                }
            }
        } else {
            param.set("");
        }

        operation.setFormatParam(null);
    }
    private void otherReqest(HttpServletRequest request,Operation operation){
        StringBuilder param = new StringBuilder();
        try {
            request.setCharacterEncoding("UTF-8");
            if (Constant.RequestMethod.Post.getMethod().equalsIgnoreCase(request.getMethod())) {
                ServletInputStream inputStream = request.getInputStream();
                StringBuilder responseStrBuilder = new StringBuilder();
                int bytesRead;
                byte[] bytes = new byte[1024 * 5];
                while ((bytesRead = inputStream.read(bytes)) > 0) {
                    responseStrBuilder.append(new String(bytes, 0, bytesRead, StandardCharsets.UTF_8));
                }
                inputStream.close();
                if (!"".equals(responseStrBuilder.toString())) {
                    param = new StringBuilder(responseStrBuilder.toString());
                } else {
                    Map<String, String[]> parameterMap = request.getParameterMap();
                    Set<String> keys = parameterMap.keySet();
                    if (!keys.isEmpty()) {
                        for (String key : keys) {
                            if (parameterMap.get(key) != null && parameterMap.get(key).length > 0) {
                                param.append(key).append(":").append(parameterMap.get(key)[0]).append(",");
                            } else {
                                param.append(key).append(": '',");
                            }
                        }
                    } else {
                        param = new StringBuilder();
                    }
                }
            }
        } catch (IOException e) {
            log.error("error：" + e);
        }
        operation.setFormatParam(param.toString());
    }
    private JSONObject requestHeader(HttpServletRequest request, Operation operation){
        try {
            //--------请求头数据-------------
            String  s = request.getHeader("userCre");
            s = URLDecoder.decode(s,"utf-8");
            JSONObject jsonObject = JSONObject.parseObject(s);
            JSONObject userInfo;
            userInfo = jsonObject.getJSONObject("credential").getJSONObject("load").getJSONObject("userInfo");
            //身份证号
            operation.setCardNo(userInfo.getString("sfzh"));
            //警号
            operation.setPoliceId(userInfo.getString("jh"));
            return jsonObject;
        }catch (Exception e){
            e.printStackTrace();
            log.info("用户为空");
        }
        return null;
    }
    private void requestBody( JSONObject jsonObject,Operation operation){
        try {
            //请求头数据
            String sn = jsonObject.getJSONObject("credential").getJSONObject("serverSign").getString("sn");
            operation.setSn(sn);
        }catch (Exception e){
            e.printStackTrace();
            log.info("证书获取失败");
        }
    }
    private void setUri(JSONObject jsonObject,Operation operation){
        try{
            String url = jsonObject.getJSONObject("credential").getJSONObject("serverSign").getString("url");
            operation.setUri(url);
            operation.setUrl(url);
        }catch (Exception e){
            e.printStackTrace();
            log.info("url为空");
        }

    }
}
